/***********************************************
 **** 版权声明处 **
 ****  为了方便阅读和维护，请严格遵守相关代码规范，谢谢   ****
 *******************************************/
package bpm.editor
{
	/*******************************************
	 **** huangjixin,2012-11-15,上午10:41:47 **
	 **** 请一句话表述该类主要作用  **
	 *******************************************/
	import bpm.event.DiagramEditorEvent;
	import bpm.graphic.Diagram;
	import bpm.graphic.Graph;
	import bpm.graphic.Link;
	import bpm.graphic.Node;
	import bpm.graphic.Renderer;
	import bpm.graphic.skins.SkinBase;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.ui.Keyboard;
	import flash.utils.Dictionary;
	
	import mx.controls.TextArea;
	import mx.core.IVisualElement;
	import mx.core.IVisualElementContainer;
	import mx.core.UIComponent;
	import mx.events.DragEvent;
	import mx.events.FlexEvent;
	import mx.events.SandboxMouseEvent;
	import mx.managers.DragManager;
	
	import spark.components.Group;
	import spark.components.supportClasses.SkinnableComponent;
	
	/**
	 * 节点创建完成事件。
	 */ 
	[Event(name="editor_create", type="bpm.event.DiagramEditorEvent")]
	/**
	 * 节点删除完成事件。
	 */ 
	[Event(name="editor_delete", type="bpm.event.DiagramEditorEvent")]
	/**
	 * 节点删除完成事件。
	 */ 
	[Event(name="editorSelectionChanged", type="bpm.event.DiagramEditorEvent")]
	/**
	 * 图表编辑器，它用于显示所有的继承自Renderer的元素。 
	 * @author huangjixin
	 * 
	 */
	public class DiagramEditor extends SkinnableComponent
	{
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// private 类私有静态变量和静态常量声明处。（全部大写，使用下划线进行分割）
		// 例如：private static const EXAMPLE:String = "example";
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		public var nodeDeepth:int = 0;
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// public 类公有静态变量和静态常量声明处。（全部大写，使用下划线进行分割）
		// 例如：public static const EXAMPLE:String = "example";
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		[SkinPart]
		public var diagram:Diagram;
		[SkinPart]
		public var diagramParent:Group;
		[SkinPart]
		public var adornersGroup:Group;
		
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// private 私有变量声明处，请以“_”开头定义变量
		// 例如：private var _example:String;
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		

		private var _cloneFunction:Function;
		
		private var _linkPrototype:Link;
		
		private var _allowEditingText:Boolean = true;
		
		private var _allowEditingTextOnCreate:Boolean = true;
		
		private var _allowCreatingLinks:Boolean = true;
		
		private var _allowDelete:Boolean = true;
		
		private var _allowDisconnectedLinks:Boolean = true;
		
		private var _allowDropping:Boolean = true;
		
		private var _allowEditing : Boolean = true;
		
		private var _allowMoving : Boolean = true;
		
		private var _allowReconnectingLinks : Boolean = true;
		
		private var _allowReparenting : Boolean = true;

		private var _allowResizing : Boolean = true;
		
		private var _autoPortsSpacing : Number = 10;
		
		private var _graph : Graph;
		
		private var selectedObjects:Vector.<Renderer> = new Vector.<Renderer>();
		
		private var _currentRenderer:Renderer;
		
		private var _currentGraph:Graph;
		
		private var rendererToAdorner:Dictionary = new Dictionary();
		
		private var _textArea : TextArea;

//		public var Diagram:Diagram;
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// public 公有变量声明处
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// 构造函数，初始化相关工作可以放在里面
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		
		public function DiagramEditor()
		{
			super();
			_textArea = new TextArea();
			addEventListener(Event.ADDED_TO_STAGE,onAddToStage);
		}//构造函数结束
		
		
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// getter和setter函数
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		
		public function get textArea():TextArea
		{
			return _textArea;
		}

		/**
		 * 是否允许重新赋予父母组件。 
		 * @return 
		 * 
		 */
		public function get allowReparenting():Boolean
		{
			return _allowReparenting;
		}
		
		public function set allowReparenting(value:Boolean):void
		{
			_allowReparenting = value;
		}

		public function get allowDropping():Boolean
		{
			return _allowDropping;
		}
		
		public function set allowDropping(value:Boolean):void
		{
			_allowDropping = value;
		}
		/**
		 * 当拷贝粘贴的时候，用于克隆对象的函数。Function used to clone objects when doing copy and paste. 
		 * @return 
		 * 
		 */
		public function get graph():Graph
		{
			return _graph;
		}
		
		/**
		 * 当拷贝粘贴的时候，用于克隆对象的函数。Function used to clone objects when doing copy and paste. 
		 * @return 
		 * 
		 */
		public function get cloneFunction():Function
		{
			return _cloneFunction;
		}
		
		public function set cloneFunction(value:Function):void
		{
			_cloneFunction = value;
		}
		
		
		/**
		 * 是否允许删除。 
		 * @return 
		 * 
		 */
		public function get allowDelete():Boolean
		{
			return _allowDelete;
		}
		
		public function set allowDelete(value:Boolean):void
		{
			_allowDelete = value;
		}
		/**
		 * 是否允许编辑文字。 
		 * @return 
		 * 
		 */
		public function get allowEditingText():Boolean
		{
			return _allowEditingText;
		}
		
		public function set allowEditingText(value:Boolean):void
		{
			_allowEditingText = value;
		}
		
		
		/**
		 * 是否允许创建完成的时候编辑文字。 
		 * @return 
		 * 
		 */
		public function get allowEditingTextOnCreate():Boolean
		{
			return _allowEditingTextOnCreate;
		}
		
		public function set allowEditingTextOnCreate(value:Boolean):void
		{
			_allowEditingTextOnCreate = value;
		}
		
		/**
		 * 连接类型。 
		 * @return 
		 * 
		 */
		public function get linkPrototype():Link
		{
			return _linkPrototype;
		}
		
		public function set linkPrototype(value:Link):void
		{
			_linkPrototype = value;
		}
		/**
		 * 用于显示图元的Diagram。 
		 * @return 
		 * 
		 */
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// 相关事件响应函数和逻辑函数存放处
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		/**
		 * 创建边饰器。 
		 * @param obj
		 * @return 
		 * 
		 */
		private function createAdorner(obj:Renderer):Adorner
		{
			var adorner:Adorner;
			if(obj is Link){
				adorner = new LinkAdorner(obj);
			}else if(obj is Node){
				adorner = new ResizableNodeAdorner(obj);
			}
			
			return adorner;
		}//createAdorner结束
		
		/**
		 *  
		 * @param obj
		 * @return 
		 * 
		 */
		private function displayAdorner(obj:Renderer):Adorner
		{
			var adorner:Adorner = getAdorner(obj);
			if(!adornersGroup.contains(adorner)){
				adornersGroup.addElement(adorner);
			}
			return adorner;
		}//createAdorner结束
		/**
		 *  
		 * @param obj
		 * @return 
		 * 
		 */
		private function clearAdorner(obj:Renderer):Adorner
		{
			var adorner:Adorner = getAdorner(obj);
			if(adornersGroup.contains(adorner)){
				adornersGroup.removeElement(adorner);
			}
			return adorner;
		}//createAdorner结束
		/**
		 * 获得节点深度。 
		 * @param node
		 * @param gra
		 * 
		 */
		private function getRendererDeepth(node:UIComponent):void{
			if(node != graph){
				nodeDeepth ++;
				getRendererDeepth(node.parent as UIComponent);
			}else{
				return;
			}
		}
		
		
		/**
		 * 
		 * 
		 */
		private function getSelectedObjs(gra:Graph):void
		{
			for (var i:int = 0; i < gra.numElements; i++) 
			{
				var ele:Renderer = gra.getElementAt(i) as Renderer;
				if(ele.isSelected){
					if(selectedObjects.indexOf(ele) == -1)
						selectedObjects.push(ele);
				}
				
				var graphEle:Graph = null;
				if(ele.hasOwnProperty("graph")){
					graphEle = ele["graph"];
				}
				
				if(graphEle){
					getSelectedObjs(graphEle);
				}
			}
		}
		
		/**
		 * DiagramEditorEvent事件综合处理。 
		 * @param event
		 * 
		 */
		private function onEditorEvent(event:DiagramEditorEvent):void
		{
			var node:Renderer = event.object as Renderer;
			var adorner:Adorner;
			switch(event.type)
			{
				case DiagramEditorEvent.EDITOR_CREATE:
				{
					//-----------------------------------
					// 节点一旦创建完毕，我们将派发事件，将该节点设置为选中状态。
					//-----------------------------------
					dispatchEvent(event);
					deselectAll();
					setSelected(node,true);
					selectedObjects.push(node);
					
					adorner = displayAdorner(node);
//					var str:String = adorner.getText();
					break;
				}
				case DiagramEditorEvent.EDITOR_DELETE:
				{
					//-----------------------------------
					// 节点一旦创建完毕，我们将派发事件，将该节点设置为选中状态。
					//-----------------------------------
					adorner = rendererToAdorner[node] as Adorner;
					if(adorner){
						adorner.cleanup();
						rendererToAdorner[node] = null;
					}
					dispatchEvent(event);
					break;
				}
					
				default:
				{
					break;
				}
			}
			
		}
		
		/**
		 * 添加到舞台的响应函数，在函数体当中添加侦听舞台移动事件，注意均在捕获阶段。 
		 * @param event
		 * 
		 */
		protected function onAddToStage(event:Event):void
		{
			stage.addEventListener(MouseEvent.MOUSE_MOVE,onStageMouseMove,true);
			stage.addEventListener(MouseEvent.MOUSE_DOWN,onStageMouseDown,true);
			stage.addEventListener(DragEvent.DRAG_ENTER,onDragEnter,true);
			stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyDown,true);
			//-----------------------
			// 侦听操作事件。
			//-----------------------
			stage.addEventListener(DiagramEditorEvent.EDITOR_CREATE,onEditorEvent);
			stage.addEventListener(DiagramEditorEvent.EDITOR_DELETE,onEditorEvent);
		}
		/**
		 * 侦听对象拖拽进来，如果有克隆函数则调用克隆函数，改变组件大小。 
		 * @param event
		 * 
		 */
		private function onDragEnter(event:DragEvent):void
		{		
			//-----------------------------------------
			// 通过坐标转换判断点击的区域是否在本地区域内，如果不是那就返回
			//-----------------------------------------
			var rect:Rectangle = graph.getRect(graph);
			var point:Point = new Point(rect.x,rect.y);
			point = localToGlobal(point);
			rect.x = point.x;
			rect.y = point.y;
			
			point = new Point(graph.mouseX,graph.mouseY);
			point = localToGlobal(point);
			if(!rect.containsPoint(point)){
				return;
			}
			
			if (event.dragSource.hasFormat(Graph.DATA_FORMAT))
			{
				if(!allowDropping){
					event.stopPropagation();
					return;
				}
				var object:Object=event.dragSource.dataForFormat(Graph.DATA_FORMAT);
				var node:Renderer=object.cloneRenderer as Renderer;
				if(cloneFunction!=null){
					cloneFunction(event.dragInitiator,node);
				}
			}
		}
		/**
		 * 键盘响应函数。 
		 * @param event
		 * 
		 */
		protected function onKeyDown(event:KeyboardEvent):void
		{
			switch(event.keyCode)
			{
				case Keyboard.DELETE:
				{
					if(allowDelete){
						deleteSelection();	
					}
					
					break;
				}
			}
		}
		
		/**
		 * 获得舞台当中最前的节点。 
		 * @param event
		 * 
		 */
		protected function onStageMouseDown(event:MouseEvent):void
		{
			if(event.cancelable){
				return;
			}
			
			//-----------------------------------------
			// 通过坐标转换判断点击的区域是否在本地区域内，如果不是那就返回
			//-----------------------------------------
			var diagramEditorEvent:DiagramEditorEvent;
			var rect:Rectangle = this.getRect(graph);
			var point:Point = new Point(rect.x,rect.y);
			point = localToGlobal(point);
			rect.x = point.x;
			rect.y = point.y;
			
			point = new Point(graph.mouseX,graph.mouseY);
			point = localToGlobal(point);
			if(!rect.containsPoint(point)){
				return;
			}
			
			//-----------------------------------------
			// 先判断是否为多选，多选则选中的图元可以拖拽，单选就拖动本身；
			//-----------------------------------------
			var renderer:Renderer;
			renderer = graph.getHitRenderer();
			graph.setFocus();
			if(renderer){
				if(!graph.contains(renderer)){
					return;
			 	}
					
				renderer.addEventListener(MouseEvent.MOUSE_DOWN, onRenderMouseDown);
				var index:int = selectedObjects.indexOf(renderer);
				//---------------------------------------------
				// 先判断鼠标的ctrl键有没有被按下。
				//---------------------------------------------
				if(event.ctrlKey){
					if(index == -1){
						setSelected(renderer,true);
						selectedObjects.push(renderer);
					}else{
						setSelected(renderer,false);
						selectedObjects.splice(index,1);
					}
				}else{
					if(index == -1){
						deselectAll();
						setSelected(renderer,true);
						selectedObjects.push(renderer);
						
						displayAdorner(renderer);
					}
				}
				/*else{
					setSelected(renderer,false);
					selectedObjects.splice(index,1);
				}*/
				
				diagramEditorEvent = new DiagramEditorEvent(DiagramEditorEvent.EDITOR_SELECTION_CHANGED,renderer);
				dispatchEvent(diagramEditorEvent);
			}else if(event.target == graph){
				deselectAll();
				
				diagramEditorEvent = new DiagramEditorEvent(DiagramEditorEvent.EDITOR_SELECTION_CHANGED,null);
				dispatchEvent(diagramEditorEvent);
			}
		}		
		
		/**
		 * 舞台鼠标弹起的时候，移除弹起侦听器，同时停止拖拽。 
		 * @param event
		 * 
		 */
		protected function onDiagramMouseUp(event:MouseEvent):void{
			this.stage.removeEventListener(MouseEvent.MOUSE_UP,onDiagramMouseUp);
			this.stopDrag();
		}
		
		/**
		 * 侦听舞台的鼠标移动，确定 
		 * @param event
		 * 
		 */
		protected function onStageMouseMove(event:MouseEvent):void
		{
			if(DragManager.isDragging){
				
			}
		}
		/**
		 * 当元素被鼠标按下的时候，做拖拽准备。 
		 * @param event
		 * 
		 */
		protected function onRenderMouseDown(event:MouseEvent):void
		{
			//--------------------------------
			// 不对不是Renderer节点做拖拽移动。
			//--------------------------------
			if(!event.currentTarget is Renderer){
				return;
			}
			//先把变量给定义好。
			var renderer:Renderer = event.currentTarget as Renderer;
			_currentRenderer = renderer;
			_currentGraph = graph.getDeeplistGraph(_currentRenderer);
			//拖拽开始。
			renderer.startDrag();
			
			renderer.stage.addEventListener(MouseEvent.MOUSE_UP, onRendererMouseUp);
			renderer.stage.addEventListener(MouseEvent.MOUSE_MOVE, onRendererMouseMove);
			
			//必须先截住事件。
			event.stopPropagation();
		}
		
		/**
		 * 鼠标移动，变换孩子父亲。 
		 * @param event
		 * 
		 */
		protected function onRendererMouseMove(event:MouseEvent):void
		{
			if(!allowReparenting){
				return;
			}
			
//			var renderer:Renderer;
			var gra:Graph = graph.getDeeplistGraph(_currentRenderer);
			var point:Point;
			if(!_currentRenderer || !gra || !graph.contains(gra)){
				return;
			}
			
			////////// 该段代码实现不同容器当中的拖拽。
			if(gra != this._currentGraph){
				if(!gra){
					return;
				}
				
				//单个进行拖拽。
				if(!gra.contain(gra,_currentRenderer)){
					
					/*point = new Point(_currentRenderer.x,_currentRenderer.y);
					point = _currentRenderer.parent.localToGlobal(point); //關鍵點；
					point = gra.globalToLocal(point);
					_currentRenderer.x = point.x;
					_currentRenderer.y = point.y;
					gra.addElement(_currentRenderer);*/
					reparent(selectedObjects,gra);
					this._currentGraph = gra;
				}
			}else{
				if(!gra.contain(gra,_currentRenderer)){
					
					/*point = new Point(_currentRenderer.x,_currentRenderer.y);
					point = _currentRenderer.parent.localToGlobal(point); //關鍵點；
					point = gra.globalToLocal(point);
					_currentRenderer.x = point.x;
					_currentRenderer.y = point.y;
					
					gra.addElement(_currentRenderer);*/
					reparent(selectedObjects,gra);
					this._currentGraph = gra;	
				}
			}
		}
		
		/**
		 * 节点鼠标弹起响应函数，停止拖拽，移除弹起侦听器，当前节点对象设置为null。 
		 * @param event
		 * 
		 */
		protected function onRendererMouseUp(event:Event):void
		{
			if(_currentRenderer){
				_currentRenderer.stage.addEventListener(MouseEvent.MOUSE_UP, onRendererMouseUp);
				_currentRenderer.stage.addEventListener(MouseEvent.MOUSE_MOVE, onRendererMouseMove);
				_currentRenderer.stopDrag();
				_currentRenderer = null;
				_currentGraph = null;
			}
		}
		
		/**
		 * 克隆节点。
		 * @param obj
		 * @return 
		 * 
		 */
		public function cloneRenderer(obj:Renderer):Renderer{
			return obj.clone();
		}
		/**
		 * 创建新连接。 
		 * @param startRenderer
		 * @param startPortPosition
		 * @param endRenderer
		 * @param endPortPosition
		 * @return 
		 * 
		 */
		public function createLink(startNode:Node, startPortPosition:String, endNode:Node, endPortPosition:String):Link{
			var link:Link = linkPrototype.clone() as Link;
			link.startNode = startNode;
			link.endNode = endNode;
			return link;
		}
		
		/**
		 * 删除选中的图元 
		 * 
		 */
		public function deleteSelection():void
		{
			if(!allowDelete){
				return;
			}
			//---------------------------------
			// 在这里我们先清空一下所有的数组，再让数组进栈，为的是在删除的时候按顺序派发事件
			//---------------------------------
			selectedObjects.splice(0,selectedObjects.length);
			getSelectedObjects();
			
			while(selectedObjects.length != 0){
				var ele:UIComponent = selectedObjects.pop();
				if(ele.parent){
					stage.dispatchEvent(new DiagramEditorEvent(DiagramEditorEvent.EDITOR_DELETE,ele));
					IVisualElementContainer(ele.parent).removeElement(ele);
				}
			}
			
			//---------------------------------
			// 清空数组。
			//---------------------------------
			selectedObjects.splice(0,selectedObjects.length);
		}
		
		/**
		 * 不选中图元 
		 * 
		 */
		public function deselectAll():void
		{
			while(selectedObjects.length != 0){
				var ele:Renderer = selectedObjects.pop();
				ele.isSelected = false;
			}
		}
		
		/**
		 * 获得节点相关联的边饰器。 
		 * @param obj
		 * @return 
		 * 
		 */
		public function getAdorner(obj:Renderer):Adorner{
			var adorner:Adorner = rendererToAdorner[obj] as Adorner;
			if(!adorner){
				adorner = createAdorner(obj);	
				rendererToAdorner[obj] = adorner;
				
				adorner.editor = this;
			}
			return adorner;
		}
		
		/**
		 * 比较两个节点的Graph，获得比较靠前的那个。 
		 * @param node1
		 * @param node2
		 * @return 
		 * 
		 */
		public function getLowestCommonGraph(node1:Node, node2:Node):Graph{
			this.nodeDeepth = 0;
			this.getRendererDeepth(node1);
			var node1Deepth:int = this.nodeDeepth;
			this.nodeDeepth = 0;
			this.getRendererDeepth(node2);
			var node2Deepth:int = this.nodeDeepth;
			return node1Deepth>node2Deepth ? node1.parent as Graph: node2.parent as Graph;
		}
		
		
		/**
		 * 获得选中的图元 
		 * 
		 */
		public function getSelectedObjects():Vector.<Renderer>
		{
			getSelectedObjs(graph);
			return selectedObjects;
		}
		
		/**
		 * 重新保存父母Graph 
		 * @param objects
		 * @param newParent
		 * @return 
		 * 
		 */
		public function reparent(objects:Vector.<Renderer>, newParent:Graph):Boolean{
			if(allowReparenting){
				var point:Point;
				for each (var renderer:Renderer in objects) 
				{
					//---------------------------------------
					// 对节点进行坐标转换，使其不偏移原来坐标。
					//---------------------------------------
					point = new Point(renderer.x,renderer.y);
					point = renderer.parent.localToGlobal(point); //關鍵點；
					point = newParent.globalToLocal(point);
					renderer.x = point.x;
					renderer.y = point.y;
					newParent.addElement(renderer);
				}
				return true;
			}else{
				return false;
			}
		}
		
		/**
		 * 设置节点选中与否 
		 * @param node
		 * @param selected
		 * 
		 */
		public function setSelected(renderer:Renderer,selected:Boolean):void
		{
			renderer.isSelected = selected;
		}//setSelected(node:Renderer,,selected:Boolean)结束
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// override 覆盖函数
		//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		override protected function partAdded(partName:String, instance:Object):void{
			super.partAdded(partName,instance);
			if(instance == diagram){
				_graph = diagram.graph;
			}
		}
		
		
	}//类结束
}//包结束